package com.zjb.demo.system.service;

import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.util.DateUtil;
import com.mybatisflex.solon.service.impl.ServiceImpl;
import com.zjb.demo.common.constant.CacheConstants;
import com.zjb.demo.common.exception.ServiceException;
import com.zjb.demo.system.domain.SysDictData;
import com.zjb.demo.system.domain.SysDictType;
import com.zjb.demo.system.domain.query.SysDictTypeQuery;
import com.zjb.demo.system.mapper.SysDictDataMapper;
import com.zjb.demo.system.mapper.SysDictTypeMapper;
import org.noear.redisx.plus.RedisBucket;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.zjb.demo.system.domain.table.SysDictTypeTableDef.SYS_DICT_TYPE;

/**
 * @author 庄佳彬
 * @since 2023/12/28 09:25
 */
@Component
public class SysDictTypeService extends ServiceImpl<SysDictTypeMapper, SysDictType> {

    @Inject
    private RedisBucket redisBucket;

    @Inject
    private SysDictDataMapper dictDataMapper;

    /**
     * 分页查询系统字典类型列表
     *
     * @param query 查询条件
     * @return 分页结果
     */
    public Page<SysDictType> pageList(SysDictTypeQuery query) {
        var page = new Page<SysDictType>(query.getPageNum(), query.getPageSize());
        return query(query).page(page);
    }

    /**
     * 根据给定的查询条件查询字典类型列表。
     *
     * @param query 查询条件对象
     * @return 符合查询条件的字典类型列表
     */
    public List<SysDictType> list(SysDictTypeQuery query) {
        return query(query).list();
    }


    /**
     * 检查字典类型是否唯一
     *
     * @param dict 待检查的字典类型
     * @return 如果数据库中存在相同的字典类型返回false，否则返回true
     */
    public boolean checkDictTypeUnique(SysDictType dict) {
        var query = QueryWrapper.create()
                .select(SYS_DICT_TYPE.DICT_ID)
                .from(SYS_DICT_TYPE)
                .where(SYS_DICT_TYPE.DICT_TYPE.eq(dict.getDictType()));
        return this.exists(query);
    }


    /**
     * 更新并缓存字典类型
     *
     * @param dict 待更新的字典类型对象
     * @return 是否成功更新
     */
    public Boolean updateAndCache(SysDictType dict) {
        return Db.txWithResult(() -> {
            var old = getById(dict.getDictId());

            var result = updateById(dict);
            if (result) {
                dictDataMapper.updateDictType(old.getDictType(), dict.getDictType());
            }
            return result;
        });
    }


    /**
     * 根据字典类型ID数组删除指定的字典类型
     *
     * @param dictIds 字典类型ID数组
     */
    public void deleteDictTypeByIds(Long[] dictIds) {
        Db.tx(() -> {
            // 遍历字典类型ID数组
            Stream.of(dictIds)
                    .forEach(dictId -> {
                        // 根据字典类型ID获取字典类型对象
                        var dictType = getById(dictId);
                        // 检查字典类型是否已分配
                        if (dictDataMapper.existsByType(dictType.getDictType())) {
                            // 如果已分配，则抛出服务异常
                            throw new ServiceException(String.format("%1$s已分配,不能删除", dictType.getDictName()));
                        }
                        // 删除指定的字典类型
                        removeById(dictId);
                    });
            // 返回成功
            return true;
        });
    }


    private QueryChain<SysDictType> query(SysDictTypeQuery query) {
        var start = DateUtil.parseDate(query.getBeginTime());
        var end = DateUtil.parseDate(query.getEndTime());
        return queryChain()
                .select(SYS_DICT_TYPE.ALL_COLUMNS)
                .from(SYS_DICT_TYPE)
                .where(SYS_DICT_TYPE.DICT_NAME.like(query.getDictName()))
                .and(SYS_DICT_TYPE.STATUS.eq(query.getStatus()))
                .and(SYS_DICT_TYPE.DICT_TYPE.like(query.getDictType()))
                .and(SYS_DICT_TYPE.CREATE_TIME.ge(start))
                .and(SYS_DICT_TYPE.CREATE_TIME.le(end));
    }


    /**
     * 重置字典缓存
     */
    public void resetDictCache() {
        redisBucket.removeByPattern(CacheConstants.SYS_DICT_KEY + "*");
        dictDataMapper.selectDictDataList()
                .parallelStream()
                .collect(Collectors.groupingBy(SysDictData::getDictType))
                .forEach((key, value) -> redisBucket.storeAndSerialize(getCacheKey(key), value.stream().sorted(Comparator.comparing(SysDictData::getDictSort)).toList()));
    }


    private void setDictData(SysDictType dict) {
        redisBucket.storeAndSerialize(getCacheKey(dict.getDictType()), null);
    }

    private void removeDictData(String key) {
        redisBucket.remove(getCacheKey(key));
    }

    private String getCacheKey(String key) {
        return CacheConstants.SYS_DICT_KEY + key;
    }

}
